package com.aloda.service.impl;

import com.aloda.cache.RedisUtils;
import com.aloda.constant.ErrorCode;
import com.aloda.constant.ExceptionConstant;
import com.aloda.constant.SystemConstant;
import com.aloda.dto.AnalysisDTO;
import com.aloda.dto.AnalysisLoginDTO;
import com.aloda.entity.LoginLog;
import com.aloda.entity.PageRecord;
import com.aloda.entity.Picture;
import com.aloda.entity.User;
import com.aloda.enums.RecordCategory;
import com.aloda.exception.BaseException;
import com.aloda.mapper.LoginLogMapper;
import com.aloda.mapper.PageRecordMapper;
import com.aloda.mapper.PictureMapper;
import com.aloda.mapper.UserMapper;
import com.aloda.properties.PicProperties;
import com.aloda.service.AnalysisService;
import com.aloda.service.PictureService;
import com.aloda.vo.AnalysisLoginVO;
import com.aloda.vo.AnalysisPicResourceVO;
import com.aloda.vo.AnalysisPicVO;
import com.aloda.vo.AnalysisUserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class AnalysisServiceImpl implements AnalysisService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private LoginLogMapper loginLogMapper;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private PicProperties picProperties;

    @Resource
    private PictureMapper pictureMapper;

    @Resource
    private PageRecordMapper pageRecordMapper;

    /**
     * 分析用户数据（TODO: 管理端不追求性能先应用此方案）
     *
     * @param analysisDTO
     * @return
     */
    @Override
    public AnalysisUserVO analysisUserData(AnalysisDTO analysisDTO) {
        // 构建时间数组
        ArrayList<LocalDate> dateList = getDateList(analysisDTO);
        // 遍历时间列表获取对应数据
        List<Long> userNums = dateList.stream().map(time -> {
            LocalDateTime endTime = LocalDateTime.of(time, LocalTime.MAX);
            LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
            userLambdaQueryWrapper.le(User::getCreateTime, endTime);
            return userMapper.selectCount(userLambdaQueryWrapper);
        }).toList();
        // 遍历用户数量列表获取每日新增用户数
        ArrayList<Long> newUserNums = new ArrayList<>();
        newUserNums.add(0L);
        for (int i = 0; i < userNums.size() - 1; i++) {
            long result = userNums.get(i + 1) - userNums.get(i);
            newUserNums.add(result);
        }
        // 封装返回数据
        AnalysisUserVO analysisUserVO = new AnalysisUserVO();
        analysisUserVO.setDateList(dateList);
        analysisUserVO.setUserNum(userNums);
        analysisUserVO.setNewUserNum(newUserNums);
        return analysisUserVO;
    }

    /**
     * 分析登录数据
     *
     * @param analysisDTO
     * @return
     */
    @Override
    public AnalysisLoginVO analysisLoginData(AnalysisDTO analysisDTO) {
        // 接收开始和结束时间
        LocalDateTime startTime = analysisDTO.getStartDate();
        LocalDateTime endTime = analysisDTO.getEndDate();
        // 时间跨度过大抛出异常
        if (Duration.between(startTime, endTime).toDays() > SystemConstant.LOGIN_MAX_SEARCH_DAY) {
            throw new BaseException(ExceptionConstant.TIME_ERROR);
        }
        // 构建时间列表
        ArrayList<LocalDateTime> times = new ArrayList<>();
        times.add(startTime);
        while (startTime.isBefore(endTime)) {
            startTime = startTime.plusHours(1L);
            times.add(startTime);
        }
        // 遍历时间列表获取对应数据
        List<Long> counts = times.stream().map(time -> {
            LambdaQueryWrapper<LoginLog> loginLogLambdaQueryWrapper = new LambdaQueryWrapper<>();
            loginLogLambdaQueryWrapper.between(LoginLog::getLoginTime, time, time.plusHours(1L));
            return loginLogMapper.selectCount(loginLogLambdaQueryWrapper);
        }).toList();
        // 封装返回对象
        AnalysisLoginVO analysisLoginVO = new AnalysisLoginVO();
        analysisLoginVO.setTimeList(times);
        analysisLoginVO.setLoginNums(counts);
        return analysisLoginVO;
    }

    /**
     * 获取在线用户数量
     *
     * @return
     */
    @Override
    public long analysisOnlineUser() {
        return redisUtils.getOnlineUserNums();
    }

    /**
     * 分析图片资源容量
     *
     * @return
     */
    @Override
    public AnalysisPicVO analysisPicCapacity() {
        // 获取总容量
        Long picResourceCapacity = picProperties.getPicResourceCapacity();
        // 获取当前占用容量
        List<Long> allPictureSize = pictureMapper.selectAllPictureSize();
        Long sum = allPictureSize.stream().mapToLong(Long::longValue).sum();
        return new AnalysisPicVO(picResourceCapacity,sum);
    }

    /**
     * 分析图片资源
     *
     * @param analysisDTO 分析参数对象
     * @return 图片资源分析结果
     */
    @Override
    public AnalysisPicResourceVO analysisPicResource(AnalysisDTO analysisDTO) {
        // 获取日期列表
        ArrayList<LocalDate> dateList = getDateList(analysisDTO);

        // 初始化结果集合
        List<Long> picSizeList = new ArrayList<>();       // 总图片大小集合
        List<Long> newPicSizeList = new ArrayList<>();    // 新增图片大小集合
        List<Long> picNumList = new ArrayList<>();        // 总图片数量集合

        // 遍历日期列表，统计每一天的图片数据
        for (LocalDate currentDate : dateList) {
            LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
            LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);

            // 查询当前日期之前的图片总大小和数量
            LambdaQueryWrapper<Picture> totalWrapper = new LambdaQueryWrapper<>();
            totalWrapper.le(Picture::getCreateTime, endOfDay); // 查询 <= 当前日期结束时间
            List<Picture> allPictures = pictureMapper.selectList(totalWrapper);

            long totalSize = allPictures.stream().mapToLong(Picture::getPictureSize).sum(); // 总大小
            long totalCount = allPictures.size();                                          // 总数量

            picSizeList.add(totalSize);   // 添加到总大小集合
            picNumList.add(totalCount);   // 添加到总数量集合

            // 查询当天新增的图片大小
            LambdaQueryWrapper<Picture> dailyWrapper = new LambdaQueryWrapper<>();
            dailyWrapper.between(Picture::getCreateTime, startOfDay, endOfDay); // 查询当天范围
            List<Picture> dailyPictures = pictureMapper.selectList(dailyWrapper);

            long dailySize = dailyPictures.stream().mapToLong(Picture::getPictureSize).sum(); // 当天新增大小
            newPicSizeList.add(dailySize); // 添加到新增大小集合
        }

        // 封装结果对象
        AnalysisPicResourceVO analysisPicResourceVO = new AnalysisPicResourceVO();
        analysisPicResourceVO.setTimeList(dateList.stream().map(LocalDate::atStartOfDay).collect(Collectors.toList())); // 转换为时间列表
        analysisPicResourceVO.setPicSizeList(picSizeList);
        analysisPicResourceVO.setNewPicSizeList(newPicSizeList);
        analysisPicResourceVO.setPicNumList(picNumList);

        return analysisPicResourceVO;
    }

    /**
     * 获取pv总数量
     *
     * @return
     */
    @Override
    public long getPV() {
        // 获取当天的数据
        long dailyPV = redisUtils.getDailyPV();
        // 获取持久化的数据
        LambdaQueryWrapper<PageRecord> pageRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        pageRecordLambdaQueryWrapper.eq(PageRecord::getCategory, RecordCategory.PV);
        List<PageRecord> pvList = pageRecordMapper.selectList(pageRecordLambdaQueryWrapper);
        long sum = pvList.stream().mapToLong(PageRecord::getNums).sum();
        return sum + dailyPV;
    }

    /**
     * 获取UV总数量
     *
     * @return
     */
    @Override
    public long getUV() {
        // 获取当天的 UV 数据
        long dailyUV = redisUtils.getDailyUV();
        // 获取持久化的 UV 数据
        LambdaQueryWrapper<PageRecord> pageRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        pageRecordLambdaQueryWrapper.eq(PageRecord::getCategory, RecordCategory.UV);
        List<PageRecord> uvList = pageRecordMapper.selectList(pageRecordLambdaQueryWrapper);
        // 计算持久化 UV 的总和
        long sum = uvList.stream().mapToLong(PageRecord::getNums).sum();
        return sum + dailyUV;
    }

    private ArrayList<LocalDate> getDateList(AnalysisDTO analysisDTO) {
        // 接收开始和结束时间
        LocalDateTime startDate = analysisDTO.getStartDate();
        LocalDateTime endDate = analysisDTO.getEndDate();
        // 时间跨度过大抛出异常
        if (Duration.between(startDate, endDate).toDays() > SystemConstant.USER_MAX_SEARCH_DAY) {
            throw new BaseException(ExceptionConstant.TIME_ERROR);
        }
        // 创建时间列表
        ArrayList<LocalDate> dateList = new ArrayList<>();
        dateList.add(startDate.toLocalDate());
        while (startDate.isBefore(endDate)) {
            startDate = startDate.plusDays(1);
            dateList.add(startDate.toLocalDate());
        }
        return dateList;
    }
}
